<template>
  <div>
    <div>
      <el-button @click="drawFeature('Point')">画点</el-button>
      <el-button @click="drawFeature('LineString')">画线</el-button>
      <el-button @click="drawFeature('Polygon')">画多边形</el-button>
      <el-button @click="drawFeature('Circle')">画圆</el-button>
      <el-button @click="removeLastPoint">撤回</el-button>
      <el-button @click="cancelDraw">取消</el-button>
      <el-button @click="clearDrawLayer">清除</el-button>
      <el-button @click="setMapCenter">设置地图中心点</el-button>
    </div>
	  <div id="mouse-position" style="padding: 15px 0">
		  <el-checkbox-group v-model="checkList">
			  <el-checkbox label="天地图影像图" @change="changImage"></el-checkbox>
			  <el-checkbox label="天地图影像标注" @change="changText"></el-checkbox>
		  </el-checkbox-group>
	  </div>
	  <div>
		  <el-radio-group v-model="radio" @change="changeRadio(radio)">
			  <el-radio :label="1">添加聚合标注</el-radio>
			  <el-radio :label="2">移除聚合标注</el-radio>
		  </el-radio-group>
	  </div>
    <div class="BasicMap" id="map" ref="map">
	    <div id="overlay-box" />
	    <div id="popup" class="ol-popup">
		    <a href="#" id="popup-closer" class="ol-popup-closer" ></a>
		    <div id="popup-content" class="popup-content"/>
	    </div>
    </div>
  </div>
</template>

<script>
import {Map,View} from 'ol';
import { Vector as VectorSource,XYZ,Cluster } from 'ol/source.js';
import Draw from 'ol/interaction/Draw.js';
import { Vector as VectorLayer,Tile as TileLayer,Heatmap} from 'ol/layer.js';
import { Fill, Stroke, Style, Text, Icon, Circle } from "ol/style";
import { Polygon as PolygonGeo, LineString as LineStringGeo, Point as PointGeo,Circle as CircleGeo,MultiPolygon } from 'ol/geom';
import Feature from 'ol/Feature'
import Overlay from "ol/Overlay";
//import sichuangAreaGeo from "@/assets/json/sichuan.json";
import wholeSichuan from '@/assets/json/wholeSichuan.json'
import trackCar from '@/assets/json/track-car.json'
import { Logger } from "sass";
export default {
	name: "BasicMap",
	components: {},
	data () {
		return {
			drawType:'',
			manualCreatedFeature: null,
			draw: null,
			layers: null,
			draw_source: null,
			draw_vector: null,
			circleInfo:{
				center: [104.07717467394993,30.71497528076172],
				radius: 0.1
			},
			circleInfos:[
				{
					center: [104.07717467394993,30.71497528076172],
					radius: 0.05
				},
				{
					center: [104.07717467394993,30.71497528076172],
					radius: 0.1
				}
			],
			checkList: [],
			// 点信息
			coordinates: [
				[104.13518347487872, 30.646482391357424],
				[104.09193430968921, 30.68424789428711],
				[103.9802072996163, 30.723901672363283]
			],
			radio:''
		}
	},
	methods: {
		initMap(){
			const styles = [
				'RoadOnDemand',
				'Aerial',
				'AerialWithLabelsOnDemand',
				'CanvasDark',
				'OrdnanceSurvey',
			];
			this.layers=[new TileLayer({
				title: "高德地图",
				source: new XYZ({
					url: 'https://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
					wrapX: false
				})
			}),
				//this.vectorLayer
			]
			this.view=new View({
				center: [104.07, 30.67],
				zoom: 6,
				projection: 'EPSG:4326',
				rotation: 0,
				/*maxZoom: 18,
				minZoom: 3,*/
			})
			this.map = new Map({
				layers: this.layers,
				target: 'map',
				view: this.view,
			});
			window.map = this.map;
			this.aciveStyle=new Style({
				fill: new Fill({color: 'rgba(255, 0, 0, 0.2)'}),
				stroke: new Stroke({color: 'red', width: 2}),
				text: new Text({ text: '●', fill: new Fill({ color: 'blue' }), font: '14px bold' }),

			})
			this.globalStyle=new Style({
				fill: new Fill({ color: 'rgba(0, 128, 255, 0.2)' }),
				stroke: new Stroke({ color: 'blue', width: 2 }),
				text: new Text({ text: '●', fill: new Fill({ color: 'red' }), font: '14px bold' }),
			})
			this.map.on('click',(evt)=>{
				window.map.forEachFeatureAtPixel(evt.pixel, (feature, layer) => {
					if(layer){
						let layers = this.map.getLayers().getArray()
						layer?.setStyle(this.aciveStyle)
					}

				})
			})
			this.addDrawLayer()
			this.addPopup()
			//this.map.getView().fit(new PolygonGeo([trackCar]))
			this.drawType&&this.addInteraction();
			return new Promise(resolve => {
				this.map.on('loadend', resolve)
			})
		},
		addInteraction(){
			this.draw_source=new VectorSource({
				wrapX: false
			})
			this.draw = new Draw({
				source: this.draw_source,
				type: this.drawType,
				/*map: this.map,
				stopClick: true,
				active: false,
				showTip: true,
				removePrevious: false,*/
				// freehand: true,
			});
			this.map.addInteraction(this.draw);
			this.draw_vector.setSource(this.draw_source)
			this.draw.on('drawend', (evt) => {
				const geometry = evt.feature.getGeometry();
				switch (this.drawType) {
					case 'LineString':
						if (geometry instanceof PolygonGeo) {
							const coordinates = geometry.getCoordinates()[0]; // 多边形只有一个外环
							console.log("线条的经纬度信息：",coordinates); // 打印所有顶点的经纬度
						} else if (geometry instanceof LineStringGeo) {
							const coordinates = geometry.getCoordinates();
							console.log("多边形的经纬度信息：",coordinates); // 打印所有顶点的经纬度
						}
						break;
					case 'Polygon':
						if (geometry instanceof PolygonGeo) {
							const coordinates = geometry.getCoordinates()[0]; // 多边形只有一个外环
							console.log("线条的经纬度信息：",coordinates); // 打印所有顶点的经纬度
						} else if (geometry instanceof LineStringGeo) {
							const coordinates = geometry.getCoordinates();
							console.log("多边形的经纬度信息：",coordinates); // 打印所有顶点的经纬度
						}
						break;
					case 'Point':
						let coordinate = geometry.getCoordinates();
						console.log('点的经纬度：', coordinate);
						break;
					case 'Circle':
						const center = geometry.getCenter();
						const data= {
							center: { lon: center[0], lat: center[1] },
							radius: geometry.getRadius()
						};
						this.manualCreatedFeature = evt.feature
						console.log('园的经纬度信息:',data)
						break;
						default:
							break;
				}
			});
		},
		drawPoint(){
			let feature = new Feature({
				geometry: new PointGeo(this.circleInfo.center),
			});
			feature.setStyle(this.getIcon());
			const pointLayer = new VectorLayer({
				source: new VectorSource({features: [feature],}),
			})
			this.map.addLayer(pointLayer);
		},
		drawCircles(){
			let features =this.circleInfos.map(item=>{
				return  new Feature({
					geometry: new CircleGeo(item.center, item.radius),
				})
			})
			const vectorSource = new VectorSource({features: features,});
			const circleLayer = new VectorLayer({
				source: vectorSource,
				style: this.globalStyle,
			})
			this.map.addLayer(circleLayer);
		},
		drawACircle(){
			let feature = new Feature({
				geometry: new CircleGeo(this.circleInfo.center, this.circleInfo.radius),
			});
			const vectorSource = new VectorSource({features: [feature],});
			const circleLayer = new VectorLayer({
				source: vectorSource,
				style: new Style({
					fill: new Fill({ color: 'red' }),
					stroke: new Stroke({ color: 'blue', width: 2 }),
				}),
				})
			this.map.addLayer(circleLayer);
		},
		addGif(){
			let _that = this;
			let mapDom = this.$refs.map;
			for (let i = 0; i < this.coordinates.length; i++){
				let oDiv = document.createElement("span");
				oDiv.id = "gif-" + i;
				mapDom.appendChild(oDiv);
				this.$nextTick(() => {
					const markerPoint = new Overlay({
						position: [
							_that.coordinates[i][0],
							_that.coordinates[i][1]
						],
						positioning: "center-center",
						element: document.getElementById("gif-" + i),
						stopEvent: false,
						width: 50,
						height: 50,
						className: "marker-gif",
						zIndex: 999
					});
					this.map.addOverlay(markerPoint);
				});
			}
		},
		addArea(geo=[]){
			if (geo.length === 0) return false;
			let areaFeature = null;
			const style=new Style({
				fill: new Fill({ color: "#4e98f444" }),
				stroke: new Stroke({
					width: 7,
					color: [71, 137, 227, 1]
				})
			})
			let areaFeatureArray=[]
			// 设置图层
			this.areaLayer = new VectorLayer({
				source: new VectorSource({
					features: []
				})
			});
			// 添加图层
			this.map.addLayer(this.areaLayer);
			geo.forEach(g=>{
				areaFeatureArray=g.features.map((lineData,index)=>{
					//let lineData = item;
					if(lineData.geometry.type === 'MultiPolygon'){
						return new Feature({
							geometry: new MultiPolygon(lineData.geometry.coordinates),
							style: style
						})
					}else if(lineData.geometry.type === 'Polygon'){
						return new Feature({
							geometry: new PolygonGeo(lineData.geometry.coordinates),
							style: style
						})
					}
				})
			})
			this.areaLayer.getSource().addFeatures(areaFeatureArray);
		},
		//设置地图中心点
		setMapCenter(){
			let newCenter = [104.55231785922284, 30.392296114385367]; // 替换为你想要设置的经度和纬度值
			this.view.animate({
				center: newCenter,
				duration:2000
			})
		},
		addPopup(){
			// 使用变量存储弹窗所需的 DOM 对象
			let container = document.getElementById("popup");
			let closer = document.getElementById("popup-closer");
			let content = document.getElementById("popup-content");

			// 创建一个弹窗 Overlay 对象
			this.overlay = new Overlay({
				element: container, //绑定 Overlay 对象和 DOM 对象的
				autoPan: true, // 定义弹出窗口在边缘点击时候可能不完整 设置自动平移效果
				autoPanAnimation: {
					duration: 250 //自动平移效果的动画时间 9毫秒
				}
			});
			// 将弹窗添加到 map 地图中
			this.map.addOverlay(this.overlay);
			let _that = this;
			/**
			 * 添加单击响应函数来处理弹窗动作
			 */
			this.map.on("click", function(evt) {
				//console.log(evt)
				// "EPSG:3857", "EPSG:4326" 转换
				let coordinate = evt.coordinate
				content.innerHTML = `
                <div>你点击了这里：</div>
                <div>经度：<span><code> ${coordinate[0]}  </code> <span>
                <div>纬度：<span><code> ${coordinate[1]}  </code> <span>
                	`;
				let hasLayers=_that.map.getLayers().getArray().length>0
				_that.overlay.setPosition(_that.drawType||hasLayers?undefined:evt.coordinate); //把 overlay 显示到指定的 x,y坐标
			});
			/**
			 * 为弹窗添加一个响应关闭的函数
			 */
			closer.onclick = function() {
				_that.overlay.setPosition(undefined);
				closer.blur();
				return false;
			};
		},
		//添加绘制点线面图层
		addDrawLayer() {
			this.draw_vector = new VectorLayer({
				source: new VectorSource(),
				//绘制好后，在地图上呈现的样式
				style: new Style({
					fill: new Fill({ color: 'rgba(0, 128, 255, 0.2)' }),
					stroke: new Stroke({ color: 'blue', width: 2 }),
					text: new Text({ text: '●', fill: new Fill({ color: 'red' }), font: '20px bold' }),
					zIndex: 100,
					//点样式继承image
					image: new Circle({
						radius: 7,
						fill: new Fill({
							color: "#ffcc33",
						}),
					}),
				}),
			});
			this.map.addLayer(this.draw_vector);
		},
		//清除绘制图层
		clearDrawLayer() {
			this.map.removeInteraction(this.draw); //移除交互
			// this.draw_vector.getSource().clear(); //清除图层上的所有要素
			this.draw_source.clear(); //清除图层上的所有要素
		},
		// 撤回操作
		removeLastPoint() {
			this.draw.removeLastPoint()
		},
		// 取消绘制
		cancelDraw() {
			this.map.removeInteraction(this.draw); //移除交互
			this.map.addOverlay(this.overlay);
			this.drawType = "";
		},
		//绘制点线面
		drawFeature(featureType = "") {
			this.drawType = featureType;
			this.map.removeInteraction(this.draw);
			this.addInteraction();
			this.map.removeOverlay(this.overlay)
		},
		changImage(checked){
			if (checked) {
				this.TiandiMap_img = new TileLayer({
					name: "天地图影像图层",
					source: new XYZ({
						url:
							"http://t0.tianditu.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=5d27dc75ca0c3bdf34f657ffe1e9881d", //parent.TiandituKey()为天地图密钥
						wrapX: false
					})
				});
				// 添加到地图上
				this.map.addLayer(this.TiandiMap_img);
			} else {
				this.map.removeLayer(this.TiandiMap_img);
			}
		},
		// 天地图影像注记图层
		changText(checked, e) {
			if (checked) {
				this.TiandiMap_cia = new TileLayer({
					name: "天地图影像注记图层",
					source: new XYZ({
						url:
							"http://t0.tianditu.com/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=5d27dc75ca0c3bdf34f657ffe1e9881d", //parent.TiandituKey()为天地图密钥
						wrapX: false
					})
				});
				// 添加到地图上
				this.map.addLayer(this.TiandiMap_cia);
			} else {
				this.map.removeLayer(this.TiandiMap_cia);
			}
		},
		getIcon() {
			return new Style({
				// 设置图片效果
				image: new Icon({
					src: require("@/assets/images/icon_map.png"),
					width: 30,
					height: 30,
				})
			});
		},
		getCameraIcon(coordinate) {
			return new Style({
				// 设置图片效果
				image: new Icon({
					src: require("@/assets/images/5摄像头.png"),
					width: 30,
					height: 30,
				}),
				/*text: new Text({
					text: "摄像头" + parseInt(coordinate[0]), // 添加文字描述
					fill: new Fill({ color: "#000" }),
					font: "12px font-size",
					offsetY: 20, // 设置文字偏移量
				}),*/
			});
		},
		addPoints(){
			const featuresArr=[]
			//设置图层
			let pointLayer = new VectorLayer({
				source: new VectorSource({
					features: []
				})
			});
			this.map.addLayer(pointLayer);
			// 循环添加feature
			this.coordinates.forEach(item=>{
				//一个feature就是一个坐标信息
				const feature = new Feature({
					geometry: new PointGeo(item),
				})
				feature.setStyle(this.getIcon())
				featuresArr.push(feature)
			})
			//批量添加feature
			pointLayer.getSource().addFeatures(featuresArr)
		},
		addHeatMap(){
			let colors = [
				"#2200FF",
				"#16D9CC",
				"#4DEE12",
				"#E8D225",
				"#EF1616"
			];
			let hatmapData = [
				{ name: "成都市" },
				{ name: "成都市" },
				{ name: "成都市" },
				{ name: "成都市" },
				{ name: "绵阳市" },
				{ name: "广安市" },
				{ name: "雅安市" },
				{ name: "自贡市" },
				{ name: "自贡市" },
				{ name: "自贡市" },
				{ name: "自贡市" },
				{ name: "自贡市" },
				{ name: "自贡市" },
				{ name: "自贡市" },
				{ name: "宜宾市" },
				{ name: "甘孜藏族自治州市" }
			];
			let codeList = {
				成都市: { center: { lng: 104.061902, lat: 30.609503 } },
				广安市: { center: { lng: 106.619126, lat: 30.474142 } },
				绵阳市: { center: { lng: 104.673612, lat: 31.492565 } },
				雅安市: { center: { lng: 103.031653, lat: 30.018895 } },
				自贡市: { center: { lng: 104.797794, lat: 29.368322 } },
				宜宾市: { center: { lng: 104.610964, lat: 28.781347 } },
				甘孜藏族自治州市: {
					center: { lng: 101.592433, lat: 30.426712 }
				}
			};
			this.layer = new Heatmap({
				source: new VectorSource(),
				blur: 30,
				radius: 15,
				gradient: colors
			});
			this.map.addLayer(this.layer);
			this.AppendFeatures(hatmapData, colors, codeList, 50)
		},
		/**
		 * 增加要素到热力图
		 */
		AppendFeatures(hatmapData, colors, points, max) {
			for (var i in hatmapData) {
				if (points[hatmapData[i].name]) {
					var coords = points[hatmapData[i].name];
					this.max = max;
					var f = new Feature({
						geometry: new PointGeo(
							[coords.center.lng, coords.center.lat]
						)
					});
					this.layer.getSource().addFeature(f);
				}
			}
		},
		/**
		 * 添加聚合图层
		 */
		addCluster(clusterData, points, clearup){
			let source = new VectorSource();
			this.clusterSource = new Cluster({
				distance: parseInt(20, 10),
				source: source
			});
			let layer = new VectorLayer({
				source: this.clusterSource,
				style: this.clusterStyle.call(this)
			});
			this.map.addLayer(layer);
			for (const key in clusterData) {
				points.forEach(e => {
					//console.log(e.id,key,e.id === key)
					if (e.id == key) {
						let point = [clusterData[key].center.lng, clusterData[key].center.lat];
						var f = new Feature({
							geometry: new PointGeo(point)
						});
						f.set("id", e.id);
						f.set("value", e.value);
						source.addFeature(f);
					}
				});
			}
		},
		clusterStyle() {
			return (feature, solution) => {
				let total = 0;
				feature.get("features").forEach((value, index) => {
					// 通过value.get("属性名") 获取设置的值
					//total += value.get("value"); // 获取累加的数值
					total +=1
				});
				return new Style({
					image: new Circle({
						radius: 15, //设置圆角大小
						stroke: new Stroke({
							color: "blue" //设置园stroke颜色
						}),
						fill: new Fill({
							color: "rgba(24,144,255,100)" //设置填充颜色
						})
					}),
					text: new Text({
						text: total.toString(), // 文字显示的数值
						fill: new Fill({
							color: "#FFF" // 文字显示的颜色
						})
					})
				});
			};
		},
		clickMap(){
			const _that = this
			this.map.on("singleclick", function(e) {
				const coordinate=e.coordinate;
				_that.addCamera(coordinate)
			});
		},
		//根据经纬度添加相机
		addCamera(coordinate){
			//设置图层
			let pointLayer = new VectorLayer({
				source: new VectorSource({
					features: [],
					zIndex: 1
				})
			});
			this.map.addLayer(pointLayer);
			// 循环添加feature
			const feature = new Feature({
				geometry: new PointGeo(coordinate),
			})
			feature.setStyle(this.getCameraIcon(coordinate))
			pointLayer.getSource().addFeatures([feature])
			// 设置文字信息
			this.addText(coordinate);
		},
		//就是添加了一个文本，只是文本的载体是 div的contentEditable属性，设置这个属性就是div可以编辑操作。
		addText(coordinate){
			const overlayBox = document.getElementById("overlay-box"); //创建一个div
			console.log(overlayBox,'overlayBox')
			const oDiv = document.createElement("span"); //创建一个span
			oDiv.contentEditable = true; //设置文字是否可编辑
			oDiv.id = coordinate[0]; //创建一个id
			var pText = document.createTextNode(
				"摄像头" + parseInt(coordinate[0])
			); //创建span的文本信息
			oDiv.appendChild(pText); //将文本信息添加到span
			overlayBox.appendChild(oDiv); //将span添加到div中
			var textInfo = new Overlay({
				position: coordinate, //设置位置
				element: document.getElementById(coordinate[0]),
				offset: [-35, 10], //设置偏移
			});
			this.map.addOverlay(textInfo);//把信息添加到addOverlay
		},
		addTrack() {
			//console.log("addTrack",trackCar)
			// 根据经纬度点位创建线
			let routeFeature = new Feature({
				type: "route",
				geometry: new LineStringGeo(trackCar),
			});
			// 创建开始图标
			const startMarker = new Feature({
				type: "startMarker",
				geometry: new PointGeo(trackCar[0]),
			});
			// 创建结束图标
			const endMarker = new Feature({
				type: "endMarker",
				geometry: new PointGeo(trackCar[trackCar.length - 1]),
			});
			// 设置样式
			let styles = {
				// 如果类型是 route 的样式
				route: new Style({
					stroke: new Stroke({
						width: 3, //线的宽度
						color: "#f6393b", //线的颜色
					}),
				}),
				// 如果类型是 geoMarker 的样式
				startMarker: new Style({
					image: new Icon({
						src: require("@/assets/images/start.png"),
						anchor: [0.5, 1.1], // 设置偏移
						width:50,
						height:50,
					}),
				}),
				endMarker: new Style({
					image: new Icon({
						src: require("@/assets/images/end.png"),
						anchor: [0.5, 1.1], // 设置偏移
						width:50,
						height:50,
					}),
				}),
			};
			// 把小车和线添加到图层
			this.vectorLayer = new VectorLayer({
				source: new VectorSource({
					features: [routeFeature, startMarker, endMarker],
				}), //线,起点的图标,终点的图标
				style: function (feature) {
					return styles[feature.get("type")];
				},
			});
		},
		changeRadio(radio){
			let clusterData = {
				1: { center: { lng: 104.061902, lat: 30.609503 } },
				2: { center: { lng: 106.619126, lat: 30.474142 } },
				3: { center: { lng: 104.673612, lat: 31.492565 } },
				4: { center: { lng: 103.031653, lat: 30.018895 } },
				5: { center: { lng: 104.797794, lat: 29.368322 } },
				6: { center: { lng: 104.610964, lat: 28.781347 } },
				7: { center: { lng: 105.064555, lat: 29.581632 } }
			};
			let points = [
				{ id:1, value: 85 },
				{ id:2, value: 36 },
				{ id:3, value: 50 },
				{ id:4, value: 555 },
				{ id:5, value: 55 },
				{ id:6, value: 666 },
				{ id:7, value: 777 }
			];
			console.log("changeRadio",radio)
			radio === 1 ? this.addCluster(clusterData, points, true) : this.removeFeatures();
		},
		removeFeatures(){
			this.clusterSource.getSource().clear();
			this.map.removeLayer(this.vectorLayer);
		}

	},
	async mounted(){
		//this.addTrack()
		await this.initMap();
		//this.addArea(wholeSichuan)
		//this.addHeatMap()
		//this.addPoints()
		//this.addGif()
		//this.drawACircle()
		//this.drawPoint()
		//this.clickMap();
		this.drawCircles()
	},
}
</script>

<style scoped>
.BasicMap {
  width: 100%;
  height: 800px;
}
.ol-popup {
	position: absolute;
	background-color: white;
	-webkit-filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
	filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
	padding: 15px;
	border-radius: 10px;
	border: 1px solid #cccccc;
	bottom: 12px;
	left: -50px;
}
.ol-popup:after,
.ol-popup:before {
	top: 100%;
	border: solid transparent;
	content: " ";
	height: 0;
	width: 0;
	position: absolute;
	pointer-events: none;
}
.ol-popup:after {
	border-top-color: white;
	border-width: 10px;
	left: 48px;
	margin-left: -10px;
}
.ol-popup:before {
	border-top-color: #cccccc;
	border-width: 11px;
	left: 48px;
	margin-left: -11px;
}
.ol-popup-closer {
	text-decoration: none;
	position: absolute;
	top: 2px;
	right: 8px;
}
.popup-content {
	width: 280px;
	display: flex;
	flex-direction: column;
	row-gap: 5px;
}
.ol-popup-closer:after {
	content: "✖";
}

</style>
<style>
.marker-gif {
	span {
		display: block;
		width: 40px;
		height: 40px;
		border-radius: 50%;
		background: url("../assets/images/fly.gif") no-repeat;
		background-size: 40px 40px;
	}
}
</style>
